package com.niiwoo.civet.trade.report;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.trade.dao.mapper.ProjectInvestOrderMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectMapperExt;
import com.niiwoo.civet.trade.property.RtsBaseProperties;
import com.niiwoo.civet.trade.report.client.report.common.ReportToTxtUtil;
import com.niiwoo.civet.trade.report.client.report.DateReportDataService;
import com.niiwoo.civet.trade.report.upload.exception.Base64Exception;
import com.niiwoo.civet.trade.report.upload.exception.EncryptDataException;
import com.niiwoo.civet.trade.report.upload.exception.HashException;
import com.niiwoo.civet.trade.report.upload.http.HttpUtil;
import com.niiwoo.civet.trade.report.upload.security.SecurityEngineClient;
import com.niiwoo.civet.user.service.UserBasicInfoDubboService;
import com.niiwoo.tripod.base.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.FormBodyPart;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.util.EntityUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.zip.ZipOutputStream;

/**
 * Created by bincun on 2018/10/23.
 */
@Slf4j
@Service
@EnableConfigurationProperties(RtsBaseProperties.class)
public class HttpUploadService {
    @Autowired
    private ProjectMapperExt projectMapperExt;
    @Autowired
    private ProjectInvestOrderMapperExt projectInvestOrderMapperExt;
    @Autowired
    private RtsBaseProperties rtsBaseProperties;
    @Reference(version = "1.0.0")
    private UserBasicInfoDubboService userBasicInfoDubboService;
    @Autowired
    private DateReportDataService dateReportDataService;


    /**
     * 金融办数据上报总入口
     * @param reportCodeList
     * @param reportDate yyyyMMdd
     */
    public void report(List<String> reportCodeList,String reportDate,boolean isAutoUpload){
        long startTime = System.currentTimeMillis();
        log.info("上报开始时间{}",DateUtils.getCurrDatetime());
        List<String> zips = this.buildDocment(reportCodeList,reportDate);
        if (!isAutoUpload){
            log.info("文件生成不自动上传");
            return;
        }
        SecurityEngineClient securityEngine = new SecurityEngineClient();
        //使用UUID 作为 加密的秘钥
        String key = UUID.randomUUID().toString().replaceAll("-", "");
        log.info("report key:{}",key);
        log.info("待上传文件{}",zips);
        for (String zipFilePath : zips) {
            try {
                securityEngine.encryptFile(key, zipFilePath); //加密文件  加密后的文件 在原文件名的基础上，追加 .cipher
                String hash =  securityEngine.hashFile(zipFilePath); //待上传的文件 进行hash计算
                log.info("数据上传hash={}",hash);
                //String result = httpUtil.multipartPost(new File(zipFilePath+".cipher"), key, hash);
                String result = this.multipartPost(new File(zipFilePath+".cipher"), key, hash);
                log.info("数据上传result={},{}",result,zipFilePath);
            } catch (Base64Exception | EncryptDataException | HashException | IOException | URISyntaxException e) {
                log.error("数据上传异常,zipFilePath={}",zipFilePath,e);
            }
        }
        log.info("上报结束，总耗时{}毫秒",System.currentTimeMillis()-startTime);

    }

    /**
     * 生成文件
     * @param reportCodeList
     * @param reportDate yyyyMMdd
     */
    public List<String> buildDocment(List<String> reportCodeList,String reportDate){

        List<String> fileNames = new ArrayList<>();//zip 文件绝对路径
        log.info("生成金融办报表参数reportCodeList={},reportDate={}",JSON.toJSONString(reportCodeList),reportDate);
        String filePath = rtsBaseProperties.getRtsBuildDocPath();
        String companyCode = rtsBaseProperties.getRtsSuccode();
        String companyType = "p2p";
        //如果没有指定上报日期，就上报前一天数据，否则按指定日期上报
        String reportDateStr = StringUtils.isEmpty(reportDate)? DateUtils.formatDate(new DateTime().minusDays(1).toDate(),DateUtils.DATE_FORMAT):reportDate;
        log.info("报表生成日期reportDateStr：{},filePath={},companyCode={},companyType={}",reportDateStr,filePath,companyCode,companyType);
        //初始化对象
        ReportToTxtUtil reportToTxtUtil = new ReportToTxtUtil(filePath,companyCode,companyType);
        //如果没有指定生成报表类型，则6张报表全部生成
        if (CollectionUtils.isEmpty(reportCodeList)){
            reportCodeList = Arrays.asList("j1001","j1002","j1003","j1004","j1005","j1006");
        }
        //j1001 项目表
        if (reportCodeList.contains("j1001")) {
            reportToTxtUtil.initReportInfo("d", "j1001", reportDateStr);
            this.doBuildData(reportToTxtUtil);
            fileNames.add(reportToTxtUtil.getZipFilePath());
        }
        //j1002 借款人
        if (reportCodeList.contains("j1002")) {
            reportToTxtUtil.initReportInfo("d", "j1002", reportDateStr);
            this.doBuildData(reportToTxtUtil);
            fileNames.add(reportToTxtUtil.getZipFilePath());
        }
        //j1003 投资人
        if (reportCodeList.contains("j1003")) {
            reportToTxtUtil.initReportInfo("d", "j1003", reportDateStr);
            this.doBuildData(reportToTxtUtil);
            fileNames.add(reportToTxtUtil.getZipFilePath());
        }
        //j1004 担保信息
        if (reportCodeList.contains("j1004")) {
            reportToTxtUtil.initReportInfo("d", "j1004", reportDateStr);
            this.doBuildData(reportToTxtUtil);
            fileNames.add(reportToTxtUtil.getZipFilePath());
        }
        //j1005 债权转让
        if (reportCodeList.contains("j1005")) {
            reportToTxtUtil.initReportInfo("d", "j1005", reportDateStr);
            this.doBuildData(reportToTxtUtil);
            fileNames.add(reportToTxtUtil.getZipFilePath());
        }
        //j1006 交易记录
        if (reportCodeList.contains("j1006")) {
            reportToTxtUtil.initReportInfo("d", "j1006", reportDateStr);
            this.doBuildData(reportToTxtUtil);
            fileNames.add(reportToTxtUtil.getZipFilePath());
        }

        return fileNames;

    }
    /**
     *  上传文件
     */
    public void upload(){

    }

    /**
     * 写文件 zip文件
     */
    private void doBuildData(ReportToTxtUtil reportToTxtUtil){
        try {
            //打开压缩流
            ZipOutputStream zipOutputStream = reportToTxtUtil.getZipOutputStream();
            Long startTime = System.currentTimeMillis();
            Long dataStartTime = 0L;
            Long dataEndTime = 0L;
            //模拟分页
            dataStartTime = System.currentTimeMillis();
            //分页数据写到压缩包中
            if ("j1001".equals(reportToTxtUtil.getReportCode())) {
                reportToTxtUtil.dataWriteToZipFile1(zipOutputStream, dateReportDataService.getJ1001Data(reportToTxtUtil.getReportDate()));
            } else if ("j1002".equals(reportToTxtUtil.getReportCode())) {
                reportToTxtUtil.dataWriteToZipFile1(zipOutputStream, dateReportDataService.getJ1002Data(reportToTxtUtil.getReportDate()));
            } else if ("j1003".equals(reportToTxtUtil.getReportCode())) {
                reportToTxtUtil.dataWriteToZipFile1(zipOutputStream, dateReportDataService.getJ1003Data(reportToTxtUtil.getReportDate()));
            } else if ("j1004".equals(reportToTxtUtil.getReportCode())) {
                reportToTxtUtil.dataWriteToZipFile1(zipOutputStream, dateReportDataService.getJ1004Data(reportToTxtUtil.getReportDate()));
            } else if ("j1005".equals(reportToTxtUtil.getReportCode())) {
                reportToTxtUtil.dataWriteToZipFile1(zipOutputStream, dateReportDataService.getJ1005Data(reportToTxtUtil.getReportDate()));
            } else if ("j1006".equals(reportToTxtUtil.getReportCode())) {
                reportToTxtUtil.dataWriteToZipFile1(zipOutputStream, dateReportDataService.getJ1006Data(reportToTxtUtil.getReportDate()));
            } else {
                throw new RuntimeException("未知的报表！");
            }
            dataEndTime = System.currentTimeMillis();
            log.info(reportToTxtUtil.getReportCode()+"写入共耗时：" + (dataEndTime - dataStartTime) + "毫秒");
            //关闭压缩流 必须
            reportToTxtUtil.closeZipOutputStream(zipOutputStream);

            Long endTime = System.currentTimeMillis();
            log.info(reportToTxtUtil.getReportCode()+"操作完成共耗时：" + (endTime - startTime) + "毫秒");
        }catch (Exception e){
            log.error("生成报表文件异常",e);
        }
    }
    /**
     * 多块Post请求
     * @return
     * @throws URISyntaxException
     * @throws ClientProtocolException
     * @throws HttpException
     * @throws IOException
     */
    public String multipartPost(File cipher, String fileKey, String fileHash) throws URISyntaxException, IOException{
        //上传的加密文件
        String message = null;
        if(null == rtsBaseProperties.getRtsReportUrl() || rtsBaseProperties.getRtsReportUrl().length() <0) { message = "请配置服务器地址"; }
        if(null == rtsBaseProperties.getRtsSigncertKey() || rtsBaseProperties.getRtsSigncertKey().length() <0) { message = "请配置证书"; }
        else if(null == rtsBaseProperties.getRtsLoginUsername() || rtsBaseProperties.getRtsLoginUsername().length() <0) { message = "请配置用户名"; }
        else if(null == rtsBaseProperties.getRtsLoginPassword() || rtsBaseProperties.getRtsLoginPassword().length() <0) { message = "请配置密码"; }
        else if(null == rtsBaseProperties.getRtsSuccode() || rtsBaseProperties.getRtsSuccode().length() <0) { message = "请配置企业社会统一信用代码"; }
        else if(null == fileHash || fileHash.length() <0) 	{ message = "fileHash不能为空"; }
        else if(null == fileKey 	|| fileKey.length() <0) 	{ message = "fileKey不能为空"; }
        else if(!cipher.exists() || !cipher.isFile()){ message = "请选择正确的文件"; }
        else if(cipher.getName().indexOf(rtsBaseProperties.getRtsSuccode())!=0){ message = "文件名不含有企业社会统一信用代码"; }
        else if(!cipher.getName().contains(".xml.cipher")
                && !cipher.getName().contains(".xml.zip.cipher")
                && !cipher.getName().contains(".txt.cipher")
                && !cipher.getName().contains(".txt.zip.cipher")){
            message = "请上传.xml.cipher 或.xml.zip.cipher 或 .txt.cipher 或.txt.zip.cipher 后缀文件 ";
        }
        else if(!cipher.getName().contains("_d.xml")
                && !cipher.getName().contains("_d_")
                && !cipher.getName().contains("_m.xml")
                && !cipher.getName().contains("_q.xml")
                && !cipher.getName().contains("_y.xml")){
            message = "文件名频度格式应该为【d】或【m】或【q】或【y】或";
        }
        else if(cipher.length() >= 1000000 *1000){//改动
            message = "文件不能大于1024M";
        }
        if(null != message){
            throw new RuntimeException(message);
        }else{
            FileBody uploadFile = new FileBody(cipher);
            String signCert = rtsBaseProperties.getRtsSigncertKey();
            log.info("证书key.signCert="+signCert);
            FormBodyPart signCertPart = new FormBodyPart("sginCert",new StringBody(signCert, ContentType.TEXT_PLAIN));
            FormBodyPart usernamePart = new FormBodyPart("userName",new StringBody(rtsBaseProperties.getRtsLoginUsername(),ContentType.TEXT_PLAIN));
            FormBodyPart passwordPart = new FormBodyPart("password",new StringBody(rtsBaseProperties.getRtsLoginPassword(),ContentType.TEXT_PLAIN));

            FormBodyPart fileUploadPart = new FormBodyPart("uploadFile",uploadFile);  //文件上传
            FormBodyPart fileHashPart = new FormBodyPart("fileHash",new StringBody(fileHash,ContentType.TEXT_PLAIN));
            FormBodyPart fileKeyPart = new FormBodyPart("fileKey",new StringBody(fileKey,ContentType.TEXT_PLAIN));
            log.info("上传数据请求参数对象signCertPart={},usernamePart={},passwordPart={},fileUploadPart={},fileHashPart={},fileKeyPart={}", JSON.toJSONString(signCertPart)
            ,JSON.toJSONString(usernamePart),JSON.toJSONString(passwordPart),JSON.toJSONString(fileUploadPart),JSON.toJSONString(fileHashPart),JSON.toJSONString(fileKeyPart));

            List<FormBodyPart> formParts = new ArrayList<>();
            formParts.add(signCertPart);
            formParts.add(usernamePart);
            formParts.add(passwordPart);
            formParts.add(fileUploadPart);
            formParts.add(fileKeyPart);
            formParts.add(fileHashPart);
            HttpResponse httpResponse = HttpUtil.getInstance().multipartPost(rtsBaseProperties.getRtsReportUrl(), null, formParts);

            log.info("上传数据响应httpResponse={}",JSON.toJSONString(httpResponse));
            if(httpResponse.getStatusLine().getStatusCode() == 200){
                log.info("上传数据success-----------");
                return EntityUtils.toString(httpResponse.getEntity());
            }else{
                log.info("上传数据failed-----------");
                return httpResponse.getStatusLine().getStatusCode()+"";
            }
        }
    }



}
